/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Engine;

import Control.ButtonEvent;
import GraphicModels.Model;
import GraphicModels.ModelLoader;
import Menus.Menu;
import Objects.GenericObject;
import Objects.MovableObject;
import Objects.StaticObject;
import Players.HumanPlayer;
import Ships.Ship;
import UserInterface.Button;
import UserInterface.ProgressBar;
import com.sun.opengl.util.BufferUtil;
import com.sun.opengl.util.GLUT;
import com.sun.opengl.util.j2d.TextRenderer;
import gleem.linalg.Vec3f;
import gleem.linalg.Vec4f;
import java.awt.Font;
import java.awt.geom.Rectangle2D;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.GLU;

/**
 * Classe responsavel por toda a manipulacao grafica.
 *
 * @author Gustavo Buzogany Eboli
 */
public final class Renderer {
    private static Renderer instanceOf;
    private Engine engine;
    private GLAutoDrawable drawable;
    private int winWidth, winHeight;
    private HumanPlayer player;
    private TreeMap movableMap;
    private ArrayList<GenericObject> staticList;
    private TreeMap selected;
    private int miniatureAngle;
    private TextRenderer txtRenderer;
    private TextRenderer btnTxtRenderer;
    private TextRenderer titleRenderer;
    private TextRenderer smallTxtRenderer;
    private int mousex, mousey;
    private ModelLoader mloader;
    private Model model0;
    private Model model2;
    private Model model3;
    private Model model4;
    private Model model5;
    private Model model6;
    private Model model7;

    private ProgressBar pHP;
    private ProgressBar pEXP;
    private ProgressBar pPower;

    private Menu menu;

    private int mode;
    private boolean clicked;

    private int btnFontSize = 12;

    /**
     * Construtor da classe
     */
    private Renderer()
    {
        txtRenderer = new TextRenderer(new Font("SansSerif", Font.BOLD, 12), true, true);
        mode = 1; // inicia desenhando o menu

        Font smallFont = new Font("SansSerif", Font.BOLD, 8);
        Font btnFont = new Font("SansSerif", Font.BOLD, 12);
        Font titleFont = new Font("SansSerif", Font.BOLD, 82);
        smallTxtRenderer = new TextRenderer(smallFont, true, true);
        btnTxtRenderer = new TextRenderer(btnFont, true, true);
        titleRenderer = new TextRenderer(titleFont, true, true);

        pHP = new ProgressBar(60, 20, 100, 10, 100, 100);
        pHP.setColor(new Vec4f(1.0f, 0.0f, 0.0f, 0.5f));
        pEXP = new ProgressBar(200, 20, 200, 10, 100, 100);
        pEXP.setColor(new Vec4f(0.0f, 0.0f, 1.0f, 0.5f));
        pPower = new ProgressBar(60, 40, 100, 10, 100, 100);
        pPower.setColor(new Vec4f(0.0f, 1.0f, 0.0f, 0.5f));
    }

    /**
     * Altera o menu que pode ser visto
     * @param menu ponteiro para o menu
     */
    public void setMenu(Menu menu)
    {
        this.menu = menu;
    }

    /**
     * Altera o tamanho da janela
     * @param width largura
     * @param height altura
     */
    public void setWindowSize(int width, int height)
    {
        this.winWidth = width;
        this.winHeight = height;
    }

    /**
     * Chamado quando a janela eh redimensionada
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public void reshape(int x, int y, int width, int height) {

        this.winHeight = height;
        this.winWidth  = width;
        
        switch(mode)
        {
            case 0:
                switchToGame();
                break;
            case 1:
                switchToMenu();
                break;

        }
    }

    /**
     * Retorna um ponteiro para a instancia singleton
     * @return
     */
    public static Renderer getInstance()
    {
        if(Renderer.instanceOf == null)
            Renderer.instanceOf = new Renderer();
        return Renderer.instanceOf;
    }

    /**
     * Altera o GLAutoDrawable
     * @param drawable
     */
    public void setDrawable(GLAutoDrawable drawable)
    {
        this.drawable = drawable;
        switchToMenu();
    }

    /**
     * Altera a engine relacionada
     * @param engine
     */
    public void setEngine(Engine engine)
    {
        this.engine = engine;
        this.player = engine.getHumanPlayer();
        this.movableMap = engine.getMovableMap();
        this.staticList = engine.getStaticList();
        this.selected   = engine.getSelected();
    }

    /**
     * Desenha!
     */
    public void draw() {
        switch(mode)
        {
            case 0: //  desenha o jogo
                drawGame(true);
                break;
            case 1: // desenha o menu inicial
                drawMenu(true);
                break;
            case 2: // desenha o menu de pausa
                drawMenu(false);
                break;
            case 3: // desenha o menu de game over
                drawMenu(false);
                drawCaptionText("Game Over", 280, winHeight-200);
                break;
        }
    }

    /**
     * Muda o modo do opengl para Ortho. Preparando para desenhar o menu.
     */
    private void switchToMenu()
    {
        GL gl = drawable.getGL();

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrtho(0, winWidth, winHeight, 0, 0, 1);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

    }

    /**
     * Muda o modo do opengl para Perspectiva. Preparando para desenhar o jogo.
     */
    private void switchToGame()
    {
        GL gl = drawable.getGL();
        GLU glu = new GLU();
        if (winHeight <= 0) { // avoid a divide by zero error!

            winHeight = 1;
        }

        final float h = (float) winWidth / (float) winHeight;
        gl.glViewport(0, 0, winWidth, winHeight);
        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, h, 1.0, 1000.0);
        gl.glMatrixMode(GL.GL_MODELVIEW);
        gl.glLoadIdentity();

    }

    /**
     * Desenha o menu atual.
     * @param background True = desenha tie fighter girando, False = desenha o jogo.
     */
    private void drawMenu(boolean background)
    {
        GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        switchToGame();
        if(background == true)
        {
            drawMenuBackground();
        } else {
            drawGame(false);
        }
        switchToMenu();

        drawButtons();
    }

    /**
     * Desenha o jogo
     * @param hud mostrar ou nao o HUD
     */
    private void drawGame(boolean hud)
    {
        Vec3f auxv;
        GL gl = drawable.getGL();
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glLoadIdentity();

        gl.glTranslatef(0.0f, 0.0f, -150.0f);

        auxv = player.getMyShip().getPos();

        gl.glTranslatef(-1 * auxv.x(), -1 * auxv.y(), -1 * auxv.z());

        drawMovable();
        drawStatic();
        drawSelectionCircle();
        drawTargetMiniature();
        if(hud == true)
            drawHUD();
    }

    /**
     * Desenha o circulo da selecao atual (alvo dos misseis)
     */
    private void drawSelectionCircle()
    {
        GL gl = drawable.getGL();

        Vec3f auxpos;
        float auxradius;

        MovableObject aux_m;
        Integer auxKey;
        Set key = selected.keySet();

        gl.glPushMatrix();
        gl.glColor4f(0.0f, 0.0f, 0.5f, 0.9f);
        Iterator it = key.iterator();
        while (it.hasNext()) {
            auxKey = (Integer) it.next();
            aux_m = (MovableObject) movableMap.get(auxKey);
            auxpos = aux_m.getPos();
            auxradius = aux_m.getSelectionRadius();

            float angle;
            gl.glBegin(GL.GL_LINE_LOOP);
            for (int i = 0; i < 40; i++) {
                angle = (float) (i * 2 * Math.PI / 40);
                gl.glVertex2f((float) (auxpos.x() + (Math.cos(angle) * auxradius)), (float) (auxpos.y() + (Math.sin(angle) * auxradius)));
            }
            gl.glEnd();

        }
        gl.glPopMatrix();
    }

    /**
     * Renderiza um objeto movel
     * @param obj objeto a ser renderizado
     * @param gl ponteiro para o GL
     */
    private void renderMovable(MovableObject obj, GL gl) {

        GLUT glut = new GLUT();

        int modelID = obj.getModelID();

        Vec3f aux_pos = obj.getPos();
        Vec3f aux_rot = obj.getEuler_ang();

        switch (modelID) {

            case 0:

                gl.glPushMatrix();

                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll


                if(obj.getClass() == Ship.class)
                {
                    gl.glDisable(GL.GL_DEPTH_TEST);

                    Ship aux = (Ship) obj;

                    float radius = aux.getRadius();
                    float shield = aux.getPowerPerc();
                    shield *= 0.3;

                    gl.glColor4f(0.0f, 0.0f, 1.0f, shield);
                    glut.glutSolidSphere(radius+3, 15, 15);

                    gl.glEnable(GL.GL_DEPTH_TEST);
                }


                gl.glColor4f(0.5f, 0.5f, 0.5f, 0.7f);
                model0.draw(gl);
                gl.glPopMatrix();
                break;

            case 1:
                obj.draw(false);
                break;

            case 2:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll

                gl.glColor4f(1.0f, 1.0f, 1.0f, 0.8f);
                model2.draw(gl);
                gl.glPopMatrix();
                break;
            case 3:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll


                model3.draw(gl);
                gl.glPopMatrix();
                break;
            case 4:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll


                model4.draw(gl);
                gl.glPopMatrix();
                break;
            case 5:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll

                gl.glColor4f(0.3f, 0.3f, 0.3f, 0.8f);
                model5.draw(gl);
                gl.glPopMatrix();
                break;
            case 6:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll


                model6.draw(gl);
                gl.glPopMatrix();
                break;
            case 7:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll


                model7.draw(gl);
                gl.glPopMatrix();
                break;
            case 8:
                gl.glPushMatrix();
                gl.glTranslatef(aux_pos.x(), aux_pos.y(), aux_pos.z());

                gl.glRotatef(aux_rot.x(), 0, 0, 1);   // yaw
                gl.glRotatef(aux_rot.y(), 0, 1, 0);   // pitch
                gl.glRotatef(aux_rot.z(), 1, 0, 0);   // roll

                gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
                gl.glBegin(GL.GL_LINE_LOOP);
                gl.glVertex3f(0, 0, 0);
                gl.glVertex3f(0, 2.0f, 0);
                gl.glEnd();


                gl.glPopMatrix();
        }
    }

    /**
     * Renderiza objeto.
     * @param modelID id do modelo a ser renderizado
     * @param gl
     */
    private void renderObject(int modelID, GL gl)
    {
        switch(modelID)
        {
            case 0:
                model0.draw(gl);
                break;
            case 2:
                model2.draw(gl);
                break;
            case 3:
                model3.draw(gl);
                break;
            case 4:
                model4.draw(gl);
                break;
            case 5:
                model5.draw(gl);
                break;
            case 6:
                model6.draw(gl);
                break;
            case 7:
                model7.draw(gl);
                break;
        }
    }

    /**
     * Desenha todos os objetos moveis
     */
    private void drawMovable()
    {
        GL gl = drawable.getGL();
        MovableObject aux_m;
        Integer auxKey;
        Set key = movableMap.keySet();

        Iterator it = key.iterator();
        while (it.hasNext()) {
            auxKey = (Integer) it.next();
            aux_m = (MovableObject) movableMap.get(auxKey);
            if (aux_m.getVisible() == true && aux_m.getCullingVisible() == true) {

                renderMovable(aux_m, gl);

                if (aux_m.getHealthBarFlag() == true) {
                    drawHealthBar(aux_m);
                }
            }
        }
    }

    /**
     * Desenha todos os objetos estaticos
     */
    private void drawStatic()
    {
        GL gl = drawable.getGL();
        StaticObject aux_s;
        Iterator it = staticList.iterator();

        gl.glPushMatrix();

        while (it.hasNext()) {
            aux_s = (StaticObject) it.next();
            aux_s.draw();
        }
        gl.glPopMatrix();
    }

    /**
     * Desenha uma string na tela, com uma fonte grande
     * @param caption
     * @param x
     * @param y
     */
    private void drawCaptionText(String caption, int x, int y)
    {
        titleRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        titleRenderer.setColor(1.0f, 1.0f, 1.0f, 0.8f);
        titleRenderer.draw(caption, x, y);
        titleRenderer.endRendering();
    }

    /**
     * Desenha uma string na tela, com uma fonte de tamanho normal.
     * @param caption
     * @param x
     * @param y
     */
    private void drawText(String caption, int x, int y)
    {
        txtRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        txtRenderer.setColor(1.0f, 1.0f, 1.0f, 0.8f);
        txtRenderer.draw(caption, x, y);
        txtRenderer.endRendering();
    }

    /**
     * Desenha um texto de tamanho normal, centralizado
     * @param caption
     * @param x
     * @param y
     */
    private void drawTextCentered(String caption, int x, int y)
    {
        Rectangle2D dim = txtRenderer.getBounds(caption);
        txtRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        txtRenderer.draw(caption, x, (int) (y + dim.getCenterY()));
        txtRenderer.endRendering();
    }

    /**
     * Desenha um texto de tamanho pequeno, centralizado
     * @param caption
     * @param x
     * @param y
     */
     private void drawSmallTextCentered(String caption, int x, int y)
    {
        Rectangle2D dim = smallTxtRenderer.getBounds(caption);
        smallTxtRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        smallTxtRenderer.draw(caption, x, (int) (y + dim.getCenterY()));
        smallTxtRenderer.endRendering();
    }

     /**
      * Desenha a HUD do jogador.
      */
    private void drawHUD()
    {
        GL gl = drawable.getGL();
        switchToMenu();

        Ship myShip = player.getMyShip();

        gl.glPushMatrix();

        drawText("HP:", 10, 10);
        pHP.setValue(myShip.getHealthPercent()*100);
        pHP.draw(drawable, winHeight);
        drawSmallTextCentered((int)myShip.getHealth()+"/"+(int)myShip.getHealth_max(), 90, 13);

        drawText("EXP:", 170, 10);
        pEXP.setValue(player.getExpPerc());
        pEXP.draw(drawable, winHeight);
        drawSmallTextCentered(player.getExp()+"/"+player.getExpNeeded(), 280, 13);

        drawText("Power:", 10, 30);
        pPower.setValue(myShip.getPowerPerc()*100);
        pPower.draw(drawable, winHeight);
        drawSmallTextCentered((int)myShip.getPower()+"/"+(int)myShip.getMaxPower(), 90, 33);

        drawText("Level: "+player.getLevel(), 10, 50);

        gl.glPopMatrix();

        switchToGame();
    }

    /**
     * Desenha a "barra de vida" dos objetos moveis
     * @param obj
     */
    private void drawHealthBar(MovableObject obj)
    {
        GL gl = drawable.getGL();
        Vec3f pos = obj.getPos();
        float healthPerc = obj.getHealthPercent();

        gl.glPushMatrix();
        gl.glTranslatef(pos.x(), pos.y() + 2.5f, pos.z());
        gl.glScalef(2f, 2f, 2f);

        gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
        gl.glBegin(GL.GL_POLYGON);
        gl.glVertex3f(-1.4f, -0.08f, 0.0f);
        gl.glVertex3f(-1.4f + 2.8f * healthPerc, -0.08f, 0.0f);
        gl.glVertex3f(-1.4f + 2.8f * healthPerc, 0.08f, 0.0f);
        gl.glVertex3f(-1.4f, 0.08f, 0.0f);
        gl.glEnd();
        gl.glPopMatrix();

    }

    /**
     * Desenha a miniatura do alvo atual.
     */
    private void drawTargetMiniature() {
        MovableObject aux = null;
        miniatureAngle++;
        if(miniatureAngle > 360)
            miniatureAngle = 0;
        GL gl = drawable.getGL();

        gl.glColor4f(0.3f, 0.3f, 1.0f, 0.9f);

        gl.glPushMatrix();

        gl.glViewport(0, winHeight-200, 200, 200);
        gl.glLoadIdentity();

        if(selected.size() > 0)
        {
            Integer auxkey = (Integer) selected.firstKey();
            aux = (MovableObject) selected.get(auxkey);
            int modelID = aux.getModelID();

            gl.glTranslatef(0.0f, 0.5f, -10.0f);
            gl.glRotatef(180, 0.0f, 0.7f, 1.0f);
            gl.glRotatef(miniatureAngle, 0.0f, 0.0f, 1.0f);

            renderObject(modelID, gl);
        }
        gl.glViewport(0, 0, winWidth, winHeight);
        
        if (aux != null) {
            txtRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
            txtRenderer.setColor(1.0f, 1.0f, 1.0f, 0.8f);
            txtRenderer.draw("Target: " + aux.getName(), 10, winHeight - 20);
            txtRenderer.endRendering();
        }
        gl.glPopMatrix();

    }

    /**
     * Desenha o fundo do menu (tie fighter girando)
     */
    private void drawMenuBackground() {
        MovableObject aux = null;
        miniatureAngle++;
        if(miniatureAngle > 360)
            miniatureAngle = 0;
        GL gl = drawable.getGL();


        gl.glColor4f(0.3f, 0.3f, 0.3f, 0.7f);

        gl.glPushMatrix();

        gl.glLoadIdentity();

        gl.glTranslatef(0.0f, 0.5f, -5.0f);
        
        gl.glRotatef(180, 0.0f, 0.7f, 1.0f);
        gl.glRotatef(miniatureAngle, 0.0f, 0.0f, 1.0f);

        renderObject(5, gl);


        gl.glPopMatrix();

    }

    /**
     * Picking! Menu ou Ray casting
     * @param x posicao X do mouse
     * @param y posicao Y do mouse
     */
    private void select(int x, int y) {
        switch(mode)
        {
            case 0: 
                gameSelect(x, y);
        }
    }

    /**
     * Ray Picking
     * @param x posicao X do mouse
     * @param y posicao Y do mouse
     */
    private void gameSelect(int x, int y)
    {
        GL gl = drawable.getGL();
        GLU glu = new GLU();

        int viewport[] = new int[4];
        double mvmatrix[] = new double[16];
        double projmatrix[] = new double[16];
        int realy = 0;// GL y coord pos
        double wcoord[] = new double[4];// wx, wy, wz;// returned xyz coords

        gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);
        gl.glGetDoublev(GL.GL_MODELVIEW_MATRIX, mvmatrix, 0);
        gl.glGetDoublev(GL.GL_PROJECTION_MATRIX, projmatrix, 0);

        realy = viewport[3] - (int) y - 1;

        // FloatBuffer z = BufferUtil.newFloatBuffer(1);
 	// gl.glReadPixels(x, realy, 1, 1, GL.GL_DEPTH_COMPONENT, GL.GL_FLOAT, z);

        glu.gluUnProject((double) x, (double) realy, 0.99432653, mvmatrix, 0, projmatrix, 0, viewport, 0, wcoord, 0);

        // System.out.println(z.get(0));

        MovableObject aux;
        Vec3f auxPos;
        Vec3f mousePos = new Vec3f((float) wcoord[0]+player.getMyShip().getPos().x(), (float) wcoord[1]+player.getMyShip().getPos().y(), 0.0f);

        Integer tempKey;

        Set key = movableMap.keySet();
        Iterator it = key.iterator();
        while (it.hasNext()) {
            tempKey = (Integer) it.next();
            aux = (MovableObject) movableMap.get(tempKey);
            if (aux.getSelectable() == true) {
                auxPos = aux.getPos();
                double dist = auxPos.minus(mousePos).lengthSquared();

                if (dist < aux.getSelectionRadius() * aux.getSelectionRadius()) {
                    if (selected.size() > 0) {
                        Integer auxKey = (Integer) selected.lastKey();
                        MovableObject temp = (MovableObject) selected.get(auxKey);
                        temp.setSelected(false);
                        selected.clear();
                    }
                    aux.setSelected(true);
                    selected.put(aux.getID(), aux);
                }
            }
        }
    }


    /**
     * Define que houve um clique
     * @param x posicao x do mouse
     * @param y posicao y do mouse
     */
    public void setClicked(int x, int y)
    {
        this.mousex = x;
        this.mousey = y;
        clicked = true;
    }

    /**
     * Processa algum clique efetuado
     */
    public void processClick()
    {
        switch(mode)
        {
            case 0:
                select(mousex, mousey);
                break;
            case 1:
                processMousePosition(mousex, mousey, menu);
                break;
            case 2: // desenha o menu principal
                processMousePosition(mousex, mousey, menu);
                break;
            case 3: // desenha o menu principal
                processMousePosition(mousex, mousey, menu);
                break;
        }
        clicked = false;
    }

    public void setMode(int mode) {
        if(mode == 0)
        {
            switchToGame();
        }
        this.mode = mode;
    }

     /**
     *
     * Carrega todos os modelos 3d
     * Tipos de modelos:
     * 0 - X-wing
     * 1 - Explosao
     * 2 - Missil
     * 3 - Caixa
     * 4 - battleship
     * 5 - tie fighter
     * 6 - turbina
     * 7 - space invader
     * 8 - tiro (laser)
     *
     */
    public void loadModel() {
        mloader = new ModelLoader();
        mloader.setDrawable(drawable);
        model0 = mloader.load("GraphicModels/x-wing.obj", null);
        model0.setScale(0.025f, 0.025f, 0.025f);
        model0.setInitialRotation(90, 270, 0);

        model2 = mloader.load("GraphicModels/perseus2.obj", null);
        model2.setScale(0.002f, 0.002f, 0.002f);
        model2.setInitialRotation(0, 0, 90);

        model3 = mloader.load("GraphicModels/box.obj", null);
        model3.setScale(0.02f, 0.02f, 0.02f);
        model3.setInitialRotation(0, 0, 0);

        model4 = mloader.load("GraphicModels/battleship.obj", null);
        model4.setScale(0.02f, 0.02f, 0.02f);
        model4.setInitialRotation(90, 180, 0);

        model5 = mloader.load("GraphicModels/tie-fighter.obj", null);
        model5.setScale(0.008f, 0.008f, 0.008f);
        model5.setInitialRotation(90, 180, 0);

        model6 = mloader.load("GraphicModels/turbine.obj", null);
        model6.setScale(0.02f, 0.02f, 0.02f);
        model6.setInitialRotation(0, 0, 0);

        model7 = mloader.load("GraphicModels/spaceinvader.obj", null);
        model7.setScale(0.008f, 0.008f, 0.008f);
        model7.setInitialRotation(0, 0, 0);
    }

    /**
     * Desenha os botoes do menu atual
     */
    private void drawButtons() {
        GL gl = drawable.getGL();

        ArrayList<Button> buttons = menu.getButtonList();
        Button aux;
        Iterator it = buttons.iterator();

        titleRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
        titleRenderer.setColor(1, 1, 1, 1);
        titleRenderer.setSmoothing(true);
        titleRenderer.draw("Spirit: Space Invaders", 60, winHeight-100);
        titleRenderer.endRendering();

        while(it.hasNext())
        {
            aux = (Button) it.next();
            Vec4f buttonColor = aux.getColor();
            Vec4f buttonCaptionColor = aux.getCaptionColor();
            gl.glPushMatrix();

            gl.glColor4f(buttonColor.x(), buttonColor.y(), buttonColor.z(), buttonColor.w());

            gl.glBegin(GL.GL_QUADS);
            gl.glVertex2f(aux.getX(), aux.getY());
            gl.glVertex2f(aux.getX(), aux.getY()+aux.getHeight());
            gl.glVertex2f(aux.getX()+aux.getWidth(), aux.getY()+aux.getHeight());
            gl.glVertex2f(aux.getX()+aux.getWidth(), aux.getY());
            gl.glEnd();

            Rectangle2D dim = btnTxtRenderer.getBounds(aux.getCaption());
            btnTxtRenderer.beginRendering(drawable.getWidth(), drawable.getHeight());
            btnTxtRenderer.setColor(buttonCaptionColor.x(), buttonCaptionColor.y(), buttonCaptionColor.z(), buttonCaptionColor.w());
            btnTxtRenderer.setSmoothing(true);
            btnTxtRenderer.draw(aux.getCaption(), (int) (aux.getX() + (aux.getWidth() / 2) - dim.getCenterX()), (int) (winHeight - aux.getY() + dim.getCenterY() - aux.getHeight() / 2));
            btnTxtRenderer.endRendering();
            
            gl.glPopMatrix();
        }
    }

    /**
     * Processa a posicao atual do mouse (MouseOver nos botoes)
     * @param mousex
     * @param mousey
     * @param currentMenu
     */
    public void processMousePosition(int mousex, int mousey, Menu currentMenu) {
        ArrayList<Button> buttons = menu.getButtonList();
        Button aux;
        Iterator it = buttons.iterator();

        if (mode != 0) {
            while (it.hasNext()) {
                aux = (Button) it.next();
                boolean result = collideButton(mousex, mousey, aux);
                if (clicked == true && result == true) {
                    aux.click(new ButtonEvent(aux));
                }
            }
        }
    }

    /**
     * Testa colisao do mouse com um botao
     * @param x posicao X do mouse
     * @param y posicao Y do mouse
     * @param btn botao a ser testado
     * @return True se colidiu, false caso contrario
     */
    private boolean collideButton(int x, int y, Button btn)
    {
        if(x >= btn.getX() && x <= btn.getX()+btn.getWidth())
        {
            if(y >= btn.getY() && y <= btn.getY()+btn.getHeight())
            {
                btn.setColliding(true);
                return true;
            }
        }
        btn.setColliding(false);
        return false;
    }
}
